home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9207.ZIP / AVKCAPT.ZIP / ACCAPT.C < prev    next >
C/C++ Source or Header  |  1992-04-03  |  14KB  |  488 lines

  1. //-------------------------------------------------------------------------
  2. //            ActionMedia II Programmer's Toolkit
  3. //            
  4. //            Windows Motion Capture Sample Program
  5. //
  6. // Application:    AvkCapt.exe
  7. // Module Name:    accapt.c
  8. //
  9. // description:    Functions to read incoming frames from the Group Buffers
  10. //        and write them out to an AVSS file using the AVKIO file
  11. //        I/O subsystem. 
  12. //
  13. // Copyright Intel Corp. 1991, 1992
  14. // All Rights Reserved.
  15. //
  16. //-------------------------------------------------------------------------
  17. //
  18. // Exported functions from this module:
  19. //
  20. //        OpenAvioFile
  21. //        CloseAvioFile
  22. //        ToggleCapture
  23. //        CaptureAvioData
  24. //
  25. //-------------------------------------------------------------------------
  26. //
  27. // Functions local to this module:
  28. //
  29. //        ReadGrpBuf
  30. //        DispAvioErr
  31. //
  32. //-------------------------------------------------------------------------
  33. #include <windows.h>
  34. #include <stdio.h>
  35. #include <memory.h>
  36. #include "avkapi.h"
  37. #include "avkio.h"
  38. #define    ACCAPT_NOEXTERNS    1
  39. #include "avkcapt.h"
  40. #include "disperr.h"
  41. #include "log.h"
  42.  
  43.  
  44. extern CAPT        Aud;
  45. extern CAPT        Vid;
  46. extern I16        AvkRet;
  47. extern HAVK        hGrp;
  48. extern WORD        CaptureSync;
  49.  
  50. AVIO_SUM_HDR    Avio;
  51. BOOL        bAvioFileExists = FALSE;
  52.  
  53. I16        AvioRet;
  54.  
  55. static BOOL    ReadGrpBuf(CAPT *, BOOL *);
  56. I16        DispAvioErr(char *pMsg);
  57.  
  58. VIDEO_SYNC    Syncs[2] = {
  59.     { 128, 128, 240, AVK_NTSC_FULL_RATE, AVK_PA_NTSC },
  60.     { 128, 153, 288, AVK_PAL_FULL_RATE,  AVK_PA_PAL  }
  61. };
  62.  
  63.  
  64. //-------------------------------------------------------------------------
  65. //FUNCTION:
  66. //    
  67. //    BOOL OpenAvioFile(pFileSpec)
  68. //
  69. //PARMS IN:
  70. //
  71. //    char *pFileSpec;    name (and path) to use to create
  72. //                new AVSS file
  73. //    
  74. //DESCRIPTION:
  75. //
  76. //    Initialize the AVIO summary header and use it to create an AVSS file.
  77. //    This function uses the AVKIO File I/O subsystem.
  78. //    
  79. //RETURN:
  80. //
  81. //    TRUE on success.
  82. //    FALSE on any error (error message box is displayed before exit).
  83. //     
  84. //-------------------------------------------------------------------------
  85.  
  86. BOOL
  87. OpenAvioFile(char *pFileSpec)
  88. {
  89.     AVIO_VID_SUM FAR    *pVid;
  90.     AVIO_AUD_SUM FAR    *pAud;
  91.     VIDEO_SYNC        *pSync;
  92.  
  93.     if (!*pFileSpec)
  94.         return DispErr("OpenAvioFile", "No file spec");
  95.                  
  96.     // Clear out the Avio structure.       
  97.  
  98.     _fmemset((char FAR *)&Avio, 0, sizeof(Avio));
  99.  
  100.     // Initialize the structure.
  101.     Avio.SumHdrSize = sizeof(AVIO_SUM_HDR);
  102.     Avio.VidSumSize = sizeof(AVIO_VID_SUM);
  103.     Avio.AudSumSize = sizeof(AVIO_AUD_SUM);
  104.  
  105.     Avio.StrmCnt = 2;
  106.     Avio.VidCnt = 1;
  107.     Avio.AudCnt = 1;
  108.  
  109.     if ((AvioRet = AvioFileAlloc((AVIO_SUM_HDR FAR *)&Avio)) < 0)
  110.         return DispAvioErr("AvioFileAlloc");
  111.  
  112.     // Fill out the video stream substructure.
  113.     
  114.     pSync = &Syncs[CaptureSync];    // sync data (NTSC or PAL)
  115.  
  116.     pVid = Avio.VidStrms;
  117.  
  118.     pVid->StrmNum = 0;         // video stream    number
  119.     pVid->Type = AVL_T_CIM;        // compressed data
  120.     pVid->SubType = AVL_ST_YVU;    // packed data
  121.     pVid->StillPeriod = AVL_CIM_RANDOM_STILL;  // freq of still frames
  122.     pVid->xRes = pSync->xResVid << 1;       // x resolution
  123.     pVid->yRes = pSync->yResVid;           // y resolution
  124.     pVid->BitmapFormat = AVK_BM_9;           // bitmap format
  125.     pVid->FrameRate = pSync->FrameRate;       // frame rate
  126.     pVid->PixelAspect = pSync->PixelAspect;       // NTSC aspect ratio
  127.     pVid->AlgCnt = 1;               // only one algorithm
  128.     pVid->AlgName[0] = AVK_RTV_2_0;           // RTV 2.0 compression alg
  129.  
  130.     // Fill out the audio stream substructure.
  131.  
  132.     pAud = Avio.AudStrms;
  133.  
  134.     pAud->StrmNum = 1;            // audio stream number
  135.     pAud->LeftVol = 100;            // left channel volume = 100%
  136.     pAud->RightVol = 100;            // right channel volume = 100%
  137.     pAud->FrameRate = pSync->FrameRate;    // frame rate
  138.     pAud->SamplesPerSecond = AUD_SAMPLE_RATE;  // audio samples-per-second
  139.     pAud->AudChannel = AVK_AUD_MIX;        // both speakers
  140.     pAud->AlgCnt = 1;            // number of algorithms 
  141.     pAud->AlgName[0] = AVK_ADPCM4;        // audio ADPCM4 algorithm
  142.  
  143.     // Now create the file with all standard AVSS headers.
  144.  
  145.     if ((AvioRet = AvioFileCreate((char far *)pFileSpec, 
  146.       (AVIO_SUM_HDR FAR *)&Avio, OF_CREATE)) < 0)
  147.         return DispAvioErr("AvioFileCreate");
  148.  
  149.     bAvioFileExists = TRUE;
  150.  
  151.     return TRUE;
  152. }
  153.  
  154. //-------------------------------------------------------------------------
  155. //FUNCTION:
  156. //    
  157. //    BOOL CloseAvioFile(VOID)
  158. //
  159. //DESCRIPTION:
  160. //
  161. //    Update and lose an AVSS file using AVKIO. AvioFileUpdate() is called
  162. //    to write current information into the AVSS file's header.
  163. //
  164. //RETURN:
  165. //
  166. //    TRUE on success.
  167. //    FALSE on any error (error message box is displayed before exit).
  168. //     
  169. //-------------------------------------------------------------------------
  170.  
  171. BOOL
  172. CloseAvioFile()
  173. {
  174.     if (bAvioFileExists == TRUE)
  175.     {
  176.         // Update the file's header with current information that
  177.         // AVKIO keeps in the Avio summary header.
  178.  
  179.         if ((AvioRet = AvioFileUpdate((AVIO_SUM_HDR FAR *)&Avio, 0)) < 0)
  180.             return DispAvioErr("AvioFileUpdate");
  181.  
  182.         // Close the file.
  183.  
  184.         if ((AvioRet = AvioFileClose((AVIO_SUM_HDR FAR *)&Avio)) < 0)
  185.             return DispAvioErr("AvioFileClose");
  186.  
  187.         bAvioFileExists = FALSE;
  188.     }
  189.     return TRUE;
  190. }
  191.  
  192. //-------------------------------------------------------------------------
  193. //FUNCTION:
  194. //    
  195. //    BOOL ToggleCapture(VOID)
  196. //
  197. //DESCRIPTION:
  198. //
  199. //    Toggles the capture state on or off.
  200. //
  201. //RETURN:
  202. //
  203. //    TRUE on success.
  204. //    FALSE on any error (error message box is displayed before exit).
  205. //     
  206. //-------------------------------------------------------------------------
  207.  
  208. BOOL
  209. ToggleCapture()
  210. {
  211.     // If no file has been opened, return.
  212.  
  213.     if (!bAvioFileExists)
  214.     {
  215.         DispMsg("You must open a file before you can capture");
  216.         return TRUE;
  217.     }
  218.  
  219.     switch(GetState())
  220.     {
  221.         case ST_MONITORING:
  222.             // If we are monitoring, turn on capture
  223.             // by starting the group.
  224.  
  225.             if ((AvkRet = AvkGrpStart(hGrp, NOW)) != OK)
  226.                 return DispAvkErr(AvkRet, "AvkGrpStart");
  227.  
  228.             ToState(ST_CAPTURING);
  229.  
  230.             break;
  231.         
  232.         case ST_CAPTURING:
  233.             // If we are already capturing, turn it off
  234.             // by pausing the group.
  235.  
  236.             if ((AvkRet = AvkGrpPause(hGrp, NOW)) != OK)
  237.                 return DispAvkErr(AvkRet, "AvkGrpPause");
  238.  
  239.             break;
  240.  
  241.         default:
  242.             // Any other state, just do nothing - no error.
  243.             break;
  244.     }
  245.     return TRUE;
  246. }
  247.             
  248. //-------------------------------------------------------------------------
  249. //FUNCTION:
  250. //    
  251. //    BOOL CaptureAvioData(VOID)
  252. //
  253. //DESCRIPTION:
  254. //
  255. //    This function retrieves frames from the Group Buffers in VRAM and
  256. //    writes them out to an AVSS file on disk.  Each iteration of the
  257. //    main loop starts by checking whether the application's video or audio
  258. //    host RAM buffer is empty, and, if so, reading a buffer-full of frames 
  259. //    from the VRAM Group Buffers. Then it loops through the video and 
  260. //    audio host RAM buffers writing out matched video and audio frames 
  261. //    to the AVSS file. When it runs out of either video or audio frames,
  262. //    it loops back to the top to retrieve more frames.  This loop continues
  263. //    until it has retrieved all of the frames currently captured in VRAM
  264. //    or it has executed CAPTURE_LOOPS times.  We use this countdown value
  265. //    to prevent the loop from executing for too long without giving the
  266. //    message loop time to run.  If frames are being captured as fast as we
  267. //    are reading them, we might otherwise never exit this loop.
  268. //    
  269. //    This function is called periodically in response to either an
  270. //    AVK_CAPTURE_DATA_AVAILABLE from AVK, or a timer tick from a user-
  271. //    initiated Windows timer.  It is the application programmer's 
  272. //    responsibility to assure that this function is called in a timely
  273. //    manner.  If AVK is capturing frames faster than the application is
  274. //    retrieving them, some frames will be lost and AVK will substitute
  275. //    dummy frames causing disruptions in playback continuity.  If this
  276. //    function runs for too long at a time, the main window's message 
  277. //    processing response will degrade.
  278. //    
  279. //RETURN:
  280. //
  281. //    TRUE on success.
  282. //    FALSE on any error (error message box is displayed before exit).
  283. //     
  284. //-------------------------------------------------------------------------
  285.  
  286. BOOL
  287. CaptureAvioData()
  288. {
  289.     static BOOL        bInUse = FALSE;
  290.     AVIO_FRM_HDR FAR    *pFrmHdr[2];    // frame header pointers
  291.                         // for video & audio
  292.     BOOL            bDataRead;
  293.     int            Ret;
  294.     U32            VidFrmSize, AudFrmSize;
  295.     WORD            Count;
  296.  
  297.  
  298.     // It is rather unlikely, but possible that we will have a re-entrancy
  299.     // problem here.  This routine is called either in response to an
  300.     // AVK_CAPTURE_DATA_AVAILABLE message or a timer tick.  Since it
  301.     // creates a message box in the case of an error, it can allow the
  302.     // message loop to process new messages before we exit it.  This 
  303.     // might result in a new timer tick or AVK message causing re-entry 
  304.     // before we have finished displaying the error message and killing 
  305.     // the process. To prevent this contingency, we use an ownership 
  306.     // semaphore.  If the semaphore is set when we enter, something has 
  307.     // gone wrong in the currently executing code, so, instead of just 
  308.     // blocking on the semaphore, the new occurrance exits.
  309.  
  310.     if (bInUse)
  311.         return TRUE;
  312.  
  313.     // Now set the semaphore to indicate that the code is executing.
  314.     // The semaphore will be cleared as the last operation before a
  315.     // successful exit.  Note that we do NOT clear the semaphore before
  316.     // exiting on an error condition, since we will be terminating 
  317.     // the app on any error here and do not want to begin executing
  318.     // this code again between this exit and the app's termination.
  319.  
  320.     bInUse = TRUE;
  321.  
  322.     // Error if no buffers have been allocated.
  323.  
  324.     if (!Vid.pBufHead || !Aud.pBufHead)
  325.         return DispErr("CaptureAvioData",
  326.             "NULL host RAM buffer pointer");
  327.  
  328.     // Number of iterations.  Without this counter, this loop might 
  329.     // end up executing for long periods of time, since data may be
  330.     // coming into a Group Buffer as fast as we can retrieve it.  
  331.     // This  counter assures that we will exit back to the main message 
  332.     // loop in a timely fashion and rely on the timer tick or the 
  333.     // AVK_CAPTURE_DATA_AVAILABLE messages to recall us.
  334.  
  335.     Count = CAPTURE_LOOPS;
  336.  
  337.     do {
  338.  
  339.         // Init the data-read flag.
  340.  
  341.         bDataRead = FALSE;
  342.  
  343.         // If either the video or audio host ram buffer is empty,
  344.         // retrieve more frames from VRAM.  bDataRead will be set to
  345.         // TRUE if either video or audio frames were read.
  346.  
  347.         if (!Vid.BufDataCnt)
  348.         {
  349.             if (!ReadGrpBuf(&Vid, &bDataRead))
  350.                 return FALSE;
  351.         }
  352.         if (!Aud.BufDataCnt)
  353.         {
  354.             if (!ReadGrpBuf(&Aud, &bDataRead))
  355.                 return FALSE;
  356.         }
  357.  
  358.         // As long as BOTH buffers have frames, we have matched 
  359.         // frames to write out. If only one buffer has data left,
  360.         // we can't write out a frame until we have retrieved 
  361.         // more frames from VRAM into the other buffer.
  362.  
  363.         while (Vid.BufDataCnt && Aud.BufDataCnt)
  364.         {
  365.             // Set the first frame pointer to the start of the
  366.             // next frame in the video buffer and the second 
  367.             // frame pointer to the start of the next frame in
  368.             // the audio buffer.
  369.  
  370.             pFrmHdr[0] = (AVIO_FRM_HDR FAR *)Vid.pBufCurr;
  371.             pFrmHdr[1] = (AVIO_FRM_HDR FAR *)Aud.pBufCurr;
  372.  
  373.             if ((Ret = AvioFileFrmWrite((AVIO_SUM_HDR FAR *)&Avio,
  374.                 pFrmHdr)) < 0)
  375.                 return DispAvioErr("AvioFileFrmWrite");
  376.  
  377.             // Increment the pointers past the current frame 
  378.             // and subtract the current frame's size from the 
  379.             // total bytes left in the buffers.
  380.  
  381.             VidFrmSize = (U32)sizeof(AVIO_FRM_HDR)
  382.                 + pFrmHdr[0]->StrmSize[0];
  383.             Vid.pBufCurr += (WORD)VidFrmSize;
  384.             Vid.BufDataCnt -= VidFrmSize;
  385.  
  386.             AudFrmSize = (U32)sizeof(AVIO_FRM_HDR)
  387.                 + pFrmHdr[1]->StrmSize[0];
  388.             Aud.pBufCurr += (WORD)AudFrmSize;
  389.             Aud.BufDataCnt -= AudFrmSize;
  390.         }
  391.  
  392.         // If we have emptied a Group Buffer or executed 'Count' 
  393.         // times, then we fall through and exit.
  394.  
  395.     } while (bDataRead && Count--);
  396.  
  397.     bInUse = FALSE;
  398.     return TRUE;
  399. }
  400.  
  401. //-------------------------------------------------------------------------
  402. //FUNCTION:
  403. //    
  404. //    BOOL ReadGrpBuf(pCapt, pbDataRead)
  405. //
  406. //PARMS IN:
  407. //    
  408. //    CAPT    *pCapt;        pointer to either the video or audio CAPT
  409. //                capture buffer control structure.
  410. //    
  411. //PARMS OUT:
  412. //    
  413. //    BOOL    *pbDataRead;    pointer to boolean flag.  This flag is set
  414. //                to TRUE if any data was retrieved. Otherwise
  415. //                its value is not changed.
  416. //    
  417. //DESCRIPTION:
  418. //
  419. //    Read newly captured frames from an AVK Group Buffer into one of
  420. //    the application's host RAM buffers. The count of bytes read is
  421. //    put in the CAPT structure's BufDataCnt element.  If any data
  422. //    is read, the caller's flag, pbDataRead is set to TRUE.
  423. //
  424. //RETURN:
  425. //
  426. //    TRUE on success.
  427. //    FALSE on any error (error message box is displayed before exit).
  428. //     
  429. //-------------------------------------------------------------------------
  430.  
  431. static BOOL
  432. ReadGrpBuf(CAPT *pCapt, BOOL *pbDataRead)
  433. {
  434.     // Only refill the buffer if it is empty
  435.     if (!pCapt->BufDataCnt)
  436.     {
  437.         // Retrieve a buffer of frames.
  438.  
  439.         if ((AvkRet = AvkGrpBufRead(pCapt->hGrpBuf, HOST_BUF_SIZE, 
  440.           pCapt->pBufHead, &pCapt->BufDataCnt, AVK_ENABLE)) != OK)
  441.             return DispAvkErr(AvkRet, "AvkGrpBufRead");
  442.  
  443.         // Set data-read flag if we read any data.
  444.  
  445.         *pbDataRead = pCapt->BufDataCnt == (U32)0 ? FALSE : TRUE;
  446.  
  447.         // Point back to start of buffer.
  448.  
  449.         pCapt->pBufCurr = pCapt->pBufHead;
  450.     }
  451.     return TRUE;
  452. }
  453.  
  454. //-------------------------------------------------------------------------
  455. //FUNCTION:
  456. //    
  457. //    I16    DispAvioErr
  458. //
  459. //PARMS IN:
  460. //
  461. //    char     *pMsg;    pointer to caller's message to be concatenated
  462. //            to the AVIO error message.
  463. //    
  464. //DESCRIPTION:
  465. //
  466. //    Display an Avio file I/O error message in a Windows message box.  This
  467. //    message includes the error value returned from the Avio function that
  468. //    failed and a caller-supplied message that can be used to identify the 
  469. //    Avio function that failed.
  470. //
  471. //RETURN:
  472. //
  473. //    FALSE to indicate an error condition.
  474. //     
  475. //-------------------------------------------------------------------------
  476.  
  477. I16
  478. DispAvioErr(char *pMsg)
  479. {
  480.     char    Buf[128];
  481.  
  482.     wsprintf((LPSTR)Buf, (LPSTR)"Avio Error 0x%04x - %s", AvioRet, 
  483.       (LPSTR)pMsg);
  484.     DispMsg(Buf);
  485.     return FALSE;
  486. }
  487.  
  488.